package com.hiv.utils;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;


/**
 * 日期工具类
 */
@Slf4j
public class DateUtils {
    /** seconds of day */
    public final static long    ONE_DAY_SECONDS      = 86400;
    /** millseconds of day */
    public final static long    ONE_DAY_MILL_SECONDS = 86400000;

    /** yyyyMMdd日期格式 */
    public final static String  SHORT_FORMAT          = "yyyyMMdd";

    /** yyyyMMddHHmmss日期格式 */
    public final static String  LONG_FORMAT           = "yyyyMMddHHmmss";

    /** yyyy/MM/dd日期格式 */
    public final static String  WEB_FORMAT            = "yyyy/MM/dd";

    /** HHmmss日期格式 */
    public final static String  TIME_FORMAT           = "HHmmss";

    /** yyyyMM日期格式 */
    public final static String  MONTH_FORMAT          = "yyyyMM";

    /** yyyy年MM月dd日 日期格式 */
    public final static String  CHINESE_DT_FORMAT      = "yyyy年MM月dd日";

    /** yyyy年MM月dd日 日期格式 */
    public final static String  CHINESE_DT_FORMAT_HMS      = "yyyy年MM月dd日 HH:mm:ss";

    /** yyyy/MM/dd HH:mm:ss日期格式 */
    public final static String  NEW_FORMAT            = "yyyy/MM/dd HH:mm:ss";

    /** yyyy/MM/dd HH:mm日期格式 */
    public final static String  NO_SECOND_FORMAT       = "yyyy/MM/dd HH:mm";

    /**
     * 私有构造函数
     */
    private DateUtils() {
    }

    /**
     * @param pattern
     * @return
     */
    public static DateFormat getNewDateFormat(String pattern) {
        DateFormat df = new SimpleDateFormat(pattern);
        df.setLenient(false);
        return df;
    }

    /**
     * @param date
     * @param format
     * @return
     */
    public static String format(Date date, String format) {
        if (date == null) {
            return null;
        }
        return new SimpleDateFormat(format).format(date);
    }

    /**
     * @param sDate
     * @return
     * @throws ParseException
     */
    public static Date parseDateNoTime(String sDate) throws ParseException {
        DateFormat dateFormat = new SimpleDateFormat(SHORT_FORMAT);
        if ((sDate == null) || (sDate.length() < SHORT_FORMAT.length())) {
            throw new ParseException("length too little", 0);
        }
        if (!StringUtils.isNumeric(sDate)) {
            throw new ParseException("not all digit", 0);
        }
        return dateFormat.parse(sDate);
    }

    /**
     * @param sDate
     * @param format
     * @return
     * @throws ParseException
     */
    public static Date parseDateNoTime(String sDate, String format) throws ParseException {
        if (StringUtils.isBlank(format)) {
            throw new ParseException("Null format. ", 0);
        }
        DateFormat dateFormat = new SimpleDateFormat(format);
        if ((sDate == null) || (sDate.length() < format.length())) {
            throw new ParseException("length too little", 0);
        }
        return dateFormat.parse(sDate);
    }

    /**
     * @param sDate
     * @param delimit
     * @return
     * @throws ParseException
     */
    public static Date parseDateNoTimeWithDelimit(String sDate, String delimit) throws ParseException {
        sDate = sDate.replaceAll(delimit, "");
        DateFormat dateFormat = new SimpleDateFormat(SHORT_FORMAT);
        if ((sDate == null) || (sDate.length() != SHORT_FORMAT.length())) {
            throw new ParseException("length not match", 0);
        }
        return dateFormat.parse(sDate);
    }

    /**
     * @param sDate
     * @return
     */
    public static Date parseDateLongFormat(String sDate) {
        DateFormat dateFormat = new SimpleDateFormat(LONG_FORMAT);
        Date d = null;
        if ((sDate != null) && (sDate.length() == LONG_FORMAT.length())) {
            try {
                d = dateFormat.parse(sDate);
            } catch (ParseException ex) {
                return null;
            }
        }
        return d;
    }

    /**
     * @param sDate
     * @return
     */
    public static Date parseDateNewFormat(String sDate) {
        DateFormat dateFormat = new SimpleDateFormat(NEW_FORMAT);
        Date d = null;
        dateFormat.setLenient(false);
        if ((sDate != null) && (sDate.length() == NEW_FORMAT.length())) {
            try {
                d = dateFormat.parse(sDate);
            } catch (ParseException ex) {
                return null;
            }
        }
        return d;
    }

    /**
     * 计算当前时间几小时之后的时间
     *
     * @param date
     * @param hours
     * @return
     */
    public static Date addHours(Date date, long hours) {
        return addMinutes(date, hours * 60);
    }

    /**
     * 计算当前时间几分钟之后的时间
     *
     * @param date
     * @param minutes
     * @return
     */
    public static Date addMinutes(Date date, long minutes) {
        return addSeconds(date, minutes * 60);
    }

    /**
     * @param date1
     * @param secs
     * @return
     */
    public static Date addSeconds(Date date1, long secs) {
        return new Date(date1.getTime() + (secs * 1000));
    }

    /**
     * 判断输入的字符串是否为合法的小时
     * @param hourStr
     * @return true/false
     */
    public static boolean isValidHour(String hourStr) {
        if (!StringUtils.isEmpty(hourStr) && StringUtils.isNumeric(hourStr)) {
            int hour = new Integer(hourStr).intValue();
            if ((hour >= 0) && (hour <= 23)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断输入的字符串是否为合法的分或秒
     * @param str
     * @return true/false
     */
    public static boolean isValidMinuteOrSecond(String str) {
        if (!StringUtils.isEmpty(str) && StringUtils.isNumeric(str)) {
            int hour = new Integer(str).intValue();

            if ((hour >= 0) && (hour <= 59)) {
                return true;
            }
        }

        return false;
    }

    /**
     * 取得新的日期
     * @param date1 日期
     * @param days 天数
     * @return 新的日期
     */
    public static Date addDays(Date date1, long days) {
        return addSeconds(date1, days * ONE_DAY_SECONDS);
    }

    /**
     * @param sDate
     * @return
     * @throws ParseException
     */
    public static String getTomorrowDateString(String sDate) throws ParseException {
        Date aDate = parseDateNoTime(sDate);
        aDate = addSeconds(aDate, ONE_DAY_SECONDS);
        return getDateString(aDate);
    }

    /**
     * @param date
     * @return
     */
    public static String getLongDateString(Date date) {
        DateFormat dateFormat = new SimpleDateFormat(LONG_FORMAT);
        return getDateString(date, dateFormat);
    }

    public static String getNowLongLDateString() {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
        String dateTime = LocalDateTime.now(ZoneOffset.of("+8")).format(formatter);
        return dateTime;
    }

    /**
     * @param date
     * @return
     */
    public static String getNewFormatDateString(Date date) {
        DateFormat dateFormat = new SimpleDateFormat(NEW_FORMAT);
        return getDateString(date, dateFormat);
    }

    /**
     * @param date
     * @param dateFormat
     * @return
     */
    public static String getDateString(Date date, DateFormat dateFormat) {
        if (date == null || dateFormat == null) {
            return null;
        }
        return dateFormat.format(date);
    }

    public static String getDateWithTimeZone(Date date) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd'T'HH:mm:ss'+08:00'");
            String sDate = sdf.format(date);
            return sDate;
        }catch (Exception e){
            log.error("getDateWithTimeZone err: {}", e.getMessage(), e);
            return "";
        }

    }

    /**
     * @param sDate
     * @return
     * @throws ParseException
     */
    public static String getYesterDayDateString(String sDate) throws ParseException {
        Date aDate = parseDateNoTime(sDate);
        aDate = addSeconds(aDate, -ONE_DAY_SECONDS);
        return getDateString(aDate);
    }

    /**
     * @return 当天的时间格式化为"yyyyMMdd"
     */
    public static String getDateString(Date date) {
        DateFormat df = getNewDateFormat(SHORT_FORMAT);
        return df.format(date);
    }

    /**
     * @param date
     * @return
     */
    public static String getWebDateString(Date date) {
        DateFormat dateFormat = getNewDateFormat(WEB_FORMAT);
        return getDateString(date, dateFormat);
    }

    /**
     * 取得“X年X月X日”的日期格式
     *
     * @param date
     * @return
     */
    public static String getChineseDateString(Date date) {
        DateFormat dateFormat = getNewDateFormat(CHINESE_DT_FORMAT);
        return getDateString(date, dateFormat);
    }

    /**
     * @param date
     * @return
     */
    public static String getChineseDate2String(Date date) {
        DateFormat dateFormat = new SimpleDateFormat(CHINESE_DT_FORMAT_HMS);
        return getDateString(date, dateFormat);
    }

    /**
     * @return
     */
    public static String getTodayString() {
        DateFormat dateFormat = getNewDateFormat(SHORT_FORMAT);
        return getDateString(new Date(), dateFormat);
    }

    /**
     * @param date
     * @return
     */
    public static String getTimeString(Date date) {
        DateFormat dateFormat = getNewDateFormat(TIME_FORMAT);
        return getDateString(date, dateFormat);
    }

    /**
     * @param days
     * @return
     */
    public static String getBeforeDayString(int days) {
        Date date = new Date(System.currentTimeMillis() - (ONE_DAY_MILL_SECONDS * days));
        DateFormat dateFormat = getNewDateFormat(SHORT_FORMAT);
        return getDateString(date, dateFormat);
    }

    /**
     * 取得两个日期间隔秒数（日期1-日期2）
     *
     * @param one 日期1
     * @param two 日期2
     * @return 间隔秒数
     */
    public static long getDiffSeconds(Date one, Date two) {
        Calendar sysDate = new GregorianCalendar();
        sysDate.setTime(one);
        Calendar failDate = new GregorianCalendar();
        failDate.setTime(two);
        return (sysDate.getTimeInMillis() - failDate.getTimeInMillis()) / 1000;
    }

    /**
     * @param one
     * @param two
     * @return
     */
    public static long getDiffMinutes(Date one, Date two) {
        Calendar sysDate = new GregorianCalendar();
        sysDate.setTime(one);
        Calendar failDate = new GregorianCalendar();
        failDate.setTime(two);
        return (sysDate.getTimeInMillis() - failDate.getTimeInMillis()) / (60 * 1000);
    }

    public static long getDiffHours(Date one, Date two) {
        Calendar sysDate = new GregorianCalendar();
        sysDate.setTime(one);
        Calendar failDate = new GregorianCalendar();
        failDate.setTime(two);
        return (sysDate.getTimeInMillis() - failDate.getTimeInMillis()) / (3600 * 1000);
    }

    /**
     * 取得两个日期的间隔天数
     *
     * @param one
     * @param two
     * @return 间隔天数
     */
    public static long getDiffDays(Date one, Date two) {
        Calendar sysDate = new GregorianCalendar();
        sysDate.setTime(one);
        Calendar failDate = new GregorianCalendar();
        failDate.setTime(two);
        return (sysDate.getTimeInMillis() - failDate.getTimeInMillis()) / (24 * 60 * 60 * 1000);
    }

    /**
     * @param dateString
     * @param days
     * @return
     */
    public static String getBeforeDayString(String dateString, int days) {
        Date date;
        DateFormat df = getNewDateFormat(SHORT_FORMAT);
        try {
            date = df.parse(dateString);
        } catch (ParseException e) {
            date = new Date();
        }
        date = new Date(date.getTime() - (ONE_DAY_MILL_SECONDS * days));
        return df.format(date);
    }

    /**
     * @param strDate
     * @return
     */
    public static boolean isValidShortDateFormat(String strDate) {
        if (strDate.length() != SHORT_FORMAT.length()) {
            return false;
        }

        try {
            Integer.parseInt(strDate);
        } catch (Exception numberFormatException) {
            return false;
        }

        DateFormat df = getNewDateFormat(SHORT_FORMAT);
        try {
            df.parse(strDate);
        } catch (ParseException e) {
            return false;
        }
        return true;
    }

    /**
     * @param strDate
     * @param delimiter
     * @return
     */
    public static boolean isValidShortDateFormat(String strDate, String delimiter) {
        String temp = strDate.replaceAll(delimiter, "");
        return isValidShortDateFormat(temp);
    }

    /**
     * 判断表示时间的字符是否为符合yyyyMMddHHmmss格式
     *
     * @param strDate
     * @return
     */
    public static boolean isValidLongDateFormat(String strDate) {
        if (strDate.length() != LONG_FORMAT.length()) {
            return false;
        }

        try {
            Long.parseLong(strDate);
        } catch (Exception numberFormatException) {
            return false;
        }

        DateFormat df = getNewDateFormat(LONG_FORMAT);
        try {
            df.parse(strDate);
        } catch (ParseException e) {
            return false;
        }
        return true;
    }

    /**
     * 判断表示时间的字符是否为符合yyyyMMddHHmmss格式
     *
     * @param strDate
     * @param delimiter
     * @return
     */
    public static boolean isValidLongDateFormat(String strDate, String delimiter) {
        String temp = strDate.replaceAll(delimiter, "");
        return isValidLongDateFormat(temp);
    }

    /**
     * @param strDate
     * @return
     */
    public static String getShortDateString(String strDate) {
        return getShortDateString(strDate, "-|/");
    }

    /**
     * @param strDate
     * @param delimiter
     * @return
     */
    public static String getShortDateString(String strDate, String delimiter) {
        if (StringUtils.isBlank(strDate)) {
            return null;
        }

        String temp = strDate.replaceAll(delimiter, "");
        if (isValidShortDateFormat(temp)) {
            return temp;
        }
        return null;
    }

    /**
     * @return
     */
    public static String getShortFirstDayOfMonth() {
        Calendar cal = Calendar.getInstance();
        Date dt = new Date();
        cal.setTime(dt);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        DateFormat df = getNewDateFormat(SHORT_FORMAT);
        return df.format(cal.getTime());
    }

    /**
     * @return
     */
    public static String getWebTodayString() {
        DateFormat df = getNewDateFormat(WEB_FORMAT);
        return df.format(new Date());
    }

    /**
     * @return
     */
    public static String getWebFirstDayOfMonth() {
        Calendar cal = Calendar.getInstance();
        Date dt = new Date();
        cal.setTime(dt);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        DateFormat df = getNewDateFormat(WEB_FORMAT);
        return df.format(cal.getTime());
    }

    /**
     * @param dateString
     * @param formatIn
     * @param formatOut
     * @return
     */
    public static String convert(String dateString, DateFormat formatIn, DateFormat formatOut) {
        try {
            Date date = formatIn.parse(dateString);
            return formatOut.format(date);
        } catch (ParseException e) {
            log.warn("convert() --- orign date error: " + dateString);
            return "";
        }
    }

    /**
     * @param dateString
     * @return
     */
    public static String convert2WebFormat(String dateString) {
        DateFormat df1 = getNewDateFormat(SHORT_FORMAT);
        DateFormat df2 = getNewDateFormat(WEB_FORMAT);
        return convert(dateString, df1, df2);
    }

    /**
     * @param dateString
     * @return
     */
    public static String convert2ChineseDtFormat(String dateString) {
        DateFormat df1 = getNewDateFormat(SHORT_FORMAT);
        DateFormat df2 = getNewDateFormat(CHINESE_DT_FORMAT);
        return convert(dateString, df1, df2);
    }

    /**
     * @param dateString
     * @return
     */
    public static String convertFromWebFormat(String dateString) {
        DateFormat df1 = getNewDateFormat(SHORT_FORMAT);
        DateFormat df2 = getNewDateFormat(WEB_FORMAT);
        return convert(dateString, df2, df1);
    }

    /**
     * @param date1
     * @param date2
     * @return
     */
    public static boolean webDateNotLessThan(String date1, String date2) {
        DateFormat df = getNewDateFormat(WEB_FORMAT);
        return dateNotLessThan(date1, date2, df);
    }

    /**
     * @param date1
     * @param date2
     * @param format
     * @return
     */
    public static boolean dateNotLessThan(String date1, String date2, DateFormat format) {
        try {
            Date d1 = format.parse(date1);
            Date d2 = format.parse(date2);

            if (d1.before(d2)) {
                return false;
            } else {
                return true;
            }
        } catch (ParseException e) {
            log.debug("dateNotLessThan() --- ParseException(" + date1 + ", " + date2 + ")");
            return false;
        }
    }

    /**
     * @param today
     * @return
     */
    public static String getEmailDate(Date today) {
        String todayStr;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日HH:mm:ss");
        todayStr = sdf.format(today);
        return todayStr;
    }

    /**
     * @param today
     * @return
     */
    public static String getSmsDate(Date today) {
        String todayStr;
        SimpleDateFormat sdf = new SimpleDateFormat("MM月dd日HH:mm");
        todayStr = sdf.format(today);
        return todayStr;
    }

    /**
     * @param date
     * @return
     */
    public static String formatMonth(Date date) {
        if (date == null) {
            return null;
        }
        return new SimpleDateFormat(MONTH_FORMAT).format(date);
    }

    /**
     * 获取系统日期的前一天日期，返回Date
     *
     * @return
     */
    public static Date getBeforeDate() {
        Date date = new Date();
        return new Date(date.getTime() - (ONE_DAY_MILL_SECONDS));
    }

    /**
     * 获得指定时间当天起点时间
     *
     * @param date
     * @return
     */
    public static Date getDayBegin(Date date) {
        DateFormat df = new SimpleDateFormat("yyyyMMdd");
        df.setLenient(false);

        String dateString = df.format(date);
        try {
            return df.parse(dateString);
        } catch (ParseException e) {
            return date;
        }
    }


    public static Date getTodayBegin() {
        LocalDateTime today_end = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
        return Date.from(today_end.atZone(ZoneId.systemDefault()).toInstant());
    }


    public static Date getTodayEnd() {
        LocalDateTime today_end = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
        return Date.from(today_end.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 判断参date上min分钟后，是否小于当前时间
     * @param date
     * @param min
     * @return
     */
    public static boolean dateLessThanNowAddMin(Date date, long min) {
        return addMinutes(date, min).before(new Date());

    }

    /**
     * @param date
     * @return
     */
    public static boolean isAfterNow(Date date) {
        if (date == null) {
            return false;
        }
        return date.compareTo(new Date()) >= 0;
    }

    /**
     * @param date
     * @return
     */
    public static boolean isBeforeNow(Date date) {
        if (date == null)
            return false;
        return date.compareTo(new Date()) < 0;
    }

    /**
     * @param date1
     * @param data2
     * @return
     */
    public static boolean isBefore(Date date1, Date data2) {
        if (date1 == null || data2 == null)
            return false;
        return date1.compareTo(data2) < 0;
    }

    //        /**
    //         * @param args
    //         */
    //        public static void main(String[] args) {
    //            System.out.println(getChineseDate2String(new Date()));
    //        }

    /**
     * @param sDate
     * @return
     * @throws ParseException
     */
    public static Date parseNoSecondFormat(String sDate) throws ParseException {
        DateFormat dateFormat = new SimpleDateFormat(NO_SECOND_FORMAT);

        if ((sDate != null) && (sDate.length() == NO_SECOND_FORMAT.length())) {
            return dateFormat.parse(sDate);
        }
        return null;
    }

    /**
     * get current timestamp
     * @return
     */
    public static long getCurrentTimestamp(){
        long unixTimestamp = Instant.now().getEpochSecond();
        return unixTimestamp;
    }


}
